home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 February / Macworld (1998-02).dmg / Control Strip Modules / Debugger Strip / debug.c next >
C/C++ Source or Header  |  1995-10-28  |  11KB  |  377 lines

  1. #include "debug.h"
  2. #include <Icons.h>
  3. #include "ControlStrip.h"
  4. #include <Gestalt.h>
  5.  
  6. /**************
  7. Debugger Strip GH, a simple demonstration of how to write a 
  8. control strip module. 11/27/94, version 1.2.1
  9. **
  10.  changes:
  11.    • added balloon help
  12.    • now use a slightly different method to determine if a debugger
  13.      is installed.
  14.    • Now use the SetupA4 routines, not because I need them here, but
  15.      you will need them if you want to use string constants while using
  16.      CodeWarrior; without A4 setup, the compiler won't be able to find
  17.      the data for declarations like:
  18.      Str255        driverName = "\p.AppleCD";
  19.      
  20. **
  21. In case you can't use the enclosed CodeWarrior project, you should 
  22. use this code to compile a code resource of type 'sdev' and resID 0, 
  23. and merge it into the enclosed control strip module.
  24.  
  25. **
  26.  
  27. This module simply drops into MacsBug when clicked.
  28. Command clicking brings up a menu of ways to drop into Macsbug. You
  29. can add different ways by adding items to the appropriate STR# resources
  30. (id 998 = menu itms and id 999 = debugger strings).
  31.  
  32. Read the OS 6 Tech note.
  33.  
  34. On the Develop Bookmark 19 CD there is another example control strip module
  35. called "MacCalender".
  36.  
  37. ControlStrip.h is now with the Universal headers.
  38.  
  39. Remember to change the creator for your own modules.
  40.  
  41. Problems I've noticed:
  42.  * SBTrackSlider appears to be broken; it doesn't return the correct value
  43.  * SBGetDetachedIndString doesn't necessarily return a null string if the 
  44.    index is invalid
  45.  * Think Reference has incorrect declarations for the icon suite routines
  46.    Use the official Apple Icons.h file.
  47.  * This module doesn't dehilite if the user drags outside its rect like 
  48.    it ought to. This is because I need to handle the mouse click manually if I 
  49.    want to be able to show a menu. .
  50.  
  51. --glenn howes
  52. grhowes@kagi.com
  53. *****************/
  54. #ifdef __MWERKS__
  55. #include <A4Stuff.h>
  56. #endif
  57.  
  58.  
  59. pascal long main (long message, long params, Rect *statusRect, GrafPtr statusPort)
  60. {
  61.     long result = 0L;
  62.     
  63. #ifdef __MWERKS__
  64.     long oldA4 = SetCurrentA4(); // needed only if you want to have inline strings
  65. #endif
  66.     switch (message)
  67.     {
  68.         case sdevPeriodicTickle: // idle routine
  69.             // result = DoCSPeriodic((MyGlobalHandle) params, statusRect, statusPort);
  70.         break;        
  71.         case sdevInitModule: // check environs, allocate globals
  72.             result = DoCSInit(); // return allocated globals handle or -1 for failure
  73.         break;
  74.         case sdevCloseModule: // release my memory
  75.             DoCSClose((MyGlobalHandle) params);
  76.         break;
  77.         case sdevFeatures: // I want to handle mouseclicks myself, and I support balloon help
  78.             result = (1L << sdevWantMouseClicks) | (1L << sdevDontAutoTrack)
  79.                 | (1L << sdevHasCustomHelp);
  80.         break;
  81.         case sdevGetDisplayWidth:
  82.             result = 16L; // size of a small icon width
  83.         break;            
  84.         case sdevDrawStatus: // draw my icon
  85.             DoCSDraw((MyGlobalHandle) params, statusRect, statusPort);
  86.         break;
  87.         case sdevMouseClick: // the mouse was clicked in my button
  88.             result = DoCSClick((MyGlobalHandle) params, statusRect, statusPort);
  89.         break;
  90.         case sdevSaveSettings: // DoCSClick must have returned a 2 sometime
  91.             DoCSSavePrefs((MyGlobalHandle) params);
  92.         break;
  93.         case sdevShowBalloonHelp:
  94.             result = DoCSBalloonHelp((MyGlobalHandle) params, statusRect);
  95.         break;
  96.         
  97.     }
  98. #ifdef __MWERKS__
  99.     SetA4( oldA4 );
  100. #endif
  101.     return (result);
  102. }
  103. long DoCSBalloonHelp(MyGlobalHandle myGlobals, Rect *statusRect)
  104. {
  105.     Str255    aString;
  106.     
  107.     SBGetDetachedIndString(aString, (*myGlobals)->utilityStrings, kHelpString);
  108.     
  109.     return (SBShowHelpString(statusRect, aString));
  110. }
  111. /***********
  112.     DoCSPeriodic, remember to uncomment the call to this routine in the main routine.
  113.       
  114.       The Control Strip will constantly be calling your module, so be a good
  115.       strip citizen. Don't use a periodic routine if you don't need to, and 
  116.       use a large kTickleLength if your periodic code routine is time consuming
  117.       I use 120 (2 seconds)
  118.     
  119. ***********/
  120. long DoCSPeriodic(MyGlobalHandle myGlobals, Rect *statusRect, GrafPtr statusPort)
  121. {
  122.     unsigned long    ticks, lastTicks;
  123.     unsigned long    mask = 1L<<31;
  124.     
  125.     ticks = TickCount();
  126.     lastTicks = (*myGlobals)->lastTicks;
  127.     if (ticks >= lastTicks // either we've waited at least kTickleLength
  128.     || ((lastTicks & mask) && !(ticks & mask)))// or mac was on for 2 years and ticks wrapped (it could happen)
  129.     {
  130.         (*myGlobals)->lastTicks = ticks + kTickleLength;
  131.         // insert your periodic code here
  132.         
  133.     }
  134.     return (0L);
  135. }
  136. /******
  137. If I returned a value with the #1 bit set (a 2 for instance) in response to
  138. a sdevPeriodicTickle or sdevMouseClick, I will receive this message
  139.  
  140. *********/
  141. void DoCSSavePrefs(MyGlobalHandle myGlobals)
  142. {
  143.     Str255        aString;
  144.     OSErr        iErr;
  145.     Handle        prefH;
  146.     if (prefH = NewHandle(sizeof(short)))
  147.     {
  148.         SBGetDetachedIndString(aString, (*myGlobals)->utilityStrings, kPrefName);
  149.         **(short**)prefH = (*myGlobals)->whichString;
  150.         iErr = SBSavePreferences(aString, prefH);
  151.         DisposeHandle(prefH);
  152.     }
  153. }
  154. /********
  155.     If the user clicks inside my module's rectangle, I'll get this message.
  156.     If my prefererences are changed, I'll return 2, otherwise 0
  157. *********/
  158. long DoCSClick(MyGlobalHandle myGlobals, Rect *statusRect, GrafPtr statusPort)
  159. {
  160.     Boolean     shiftPressed, commandPressed, inMyRect=true;
  161.     Point        localPnt;
  162.     long        retVal = 0L;
  163.     short        oldIndex, newIndex;
  164.     MenuHandle    hMenu;
  165.     Str255        debugString;
  166.     
  167.     shiftPressed =  IsPressed(kShiftKey);
  168.     commandPressed = IsPressed(kCommandKey);
  169.     
  170.     if (commandPressed) // present a configuration menu
  171.     {
  172.         hMenu = MakePrefsMenu(myGlobals);
  173.         if (hMenu)
  174.         {
  175.             oldIndex = (*myGlobals)->whichString;
  176.             newIndex = SBTrackPopupMenu(statusRect, hMenu);
  177.             if (newIndex && newIndex != oldIndex)
  178.             {
  179.                 (*myGlobals)->whichString = newIndex;
  180.                 retVal = (1L<< sdevNeedToSave);// set preference changed flag
  181.             }
  182.             DisposeMenu(hMenu);
  183.         }
  184.         if (!shiftPressed || !newIndex) return (retVal);
  185.         // else execute immediately (inMyRect was initialized to true)
  186.     }
  187.     else // manually track mouse
  188.     {
  189.         do
  190.         {
  191.             GetMouse(&localPnt);
  192.             inMyRect = PtInRect(localPnt,statusRect);
  193.         }while (StillDown());
  194.     }
  195.     if (inMyRect)
  196.     {
  197.         SBGetDetachedIndString(debugString, 
  198.                 (*myGlobals)->debuggerStrings, (*myGlobals)->whichString);
  199.         
  200.         if (debugString[0])
  201.             DebugStr(debugString);
  202.         else
  203.             Debugger();
  204.     }
  205.     return (retVal);
  206. }
  207.  
  208. MenuHandle MakePrefsMenu(MyGlobalHandle myGlobals)
  209. {
  210.     MenuHandle    retVal = 0L;
  211.     Str255        menuItem;
  212.     Str63        dummy;
  213.     short        item = 1, numItems;
  214.     short        **numItemsH;
  215.     dummy[0] = 0;
  216.     retVal = NewMenu(702,dummy); // arbitrary menu id, no title
  217.     
  218.     if (retVal)
  219.     {    
  220.         numItemsH = (short**) (*myGlobals)->menuStrings;
  221.         numItems = **numItemsH; // manually find out how many strings I have
  222.         for(item = 1; item<= numItems; item++)
  223.         {
  224.             SBGetDetachedIndString(menuItem, (*myGlobals)->menuStrings, item);
  225.  
  226.             AppendMenu(retVal,menuItem); // note that the string shouldn't start with a -
  227.                                         // unless you want a grey line
  228.         }
  229.         if ((*myGlobals)->whichString <= numItems)
  230.             SetItemMark(retVal,(*myGlobals)->whichString,sdevMenuItemMark); // the bullet
  231.     }
  232.     return(retVal);
  233. }
  234. /*
  235.     DoCSInit -- returns a handle to my allocated globals or -1 if the environment is
  236.     wrong or I couldn't allocate my memory/load my resources
  237. */
  238. long DoCSInit(void)
  239. {
  240.     MyGlobalHandle    myH;
  241.     OSErr            iErr;
  242.     Handle            iconSuite = 0L;
  243.     Handle            menuStrings, debugStrings, utilityStrings;
  244.     Str255            prefName;
  245.     short            **whichStringH;
  246.     if (HasDebugger()) // is a debugger installed?
  247.     {
  248.         myH = (MyGlobalHandle) NewHandleClear(sizeof(MyGlobals));
  249.         iErr = SBGetDetachIconSuite(&iconSuite, 669, 0x0000FF00L);
  250.         menuStrings = GetDetachedStrings(kMenuStrings);
  251.         debugStrings = GetDetachedStrings(kDebuggerStrings);
  252.         utilityStrings = GetDetachedStrings(kUtilityStrings);
  253.         
  254.         if (myH && iconSuite && menuStrings && debugStrings && utilityStrings) 
  255.         // was I able to allocate my memory?
  256.         {
  257.             (*myH)->menuStrings = menuStrings;
  258.             (*myH)->debuggerStrings = debugStrings;
  259.             (*myH)->utilityStrings = utilityStrings;
  260.             (*myH)->iconSuite = iconSuite;
  261.             
  262.             SBGetDetachedIndString(prefName, utilityStrings, kPrefName);
  263.             iErr = SBLoadPreferences(prefName, (Handle*) &whichStringH);
  264.             if (!iErr && whichStringH)
  265.             {
  266.                 (*myH)->whichString = **whichStringH;
  267.                 DisposeHandle((Handle)whichStringH);
  268.             }
  269.             else (*myH)->whichString = 1; // default
  270.             
  271.             return ((long) myH); // return my globals
  272.         }
  273.         else // failed to allocate all my needed memory
  274.         {
  275.             if(myH) DisposeHandle((Handle) myH);
  276.             if(iconSuite) DisposeIconSuite (iconSuite, true);
  277.             if (menuStrings) DisposeHandle(menuStrings);
  278.             if (debugStrings) DisposeHandle(debugStrings);
  279.             if (utilityStrings) DisposeHandle(utilityStrings);
  280.         }
  281.     }
  282.     return (-1L); // something went wrong, don't install
  283. }
  284. /*
  285.     DoCSClose, basically just deallocate all my memory
  286. */
  287. void DoCSClose(MyGlobalHandle myGlobals)
  288. {
  289.     if (myGlobals) 
  290.     {
  291.          DisposeIconSuite ((*myGlobals)->iconSuite, true);
  292.         DisposeHandle((*myGlobals)->menuStrings);
  293.         DisposeHandle((*myGlobals)->debuggerStrings);
  294.         DisposeHandle((*myGlobals)->utilityStrings);
  295.         DisposeHandle((Handle) myGlobals);
  296.     }
  297. }
  298. /*
  299.     DoCSDraw, just draw my icon. Remember that sometimes the rectangle
  300.     that  gets  passed will be narrower than the one expected (if your module
  301.     is the last visible module and the strip isn't long enough to draw the
  302.     whole thing.
  303. */
  304. void DoCSDraw(MyGlobalHandle myGlobals, Rect *statusRect, GrafPtr statusPort)
  305. {
  306.     OSErr        iErr;
  307.     short        alignment = kAlignAbsoluteCenter; // center up & down , and left & right
  308.     long        transform = kTransformNone; // no transform
  309.     Rect         iconRect;
  310.     if ((*myGlobals)->iconSuite)
  311.     {
  312.         iconRect.left = statusRect->left; iconRect.top = statusRect->top;
  313.         iconRect.bottom = statusRect->bottom;
  314.         iconRect.right = iconRect.left + 16; // I don't want icon squished if the 
  315.                                         // status rect is too narrow (rely on clipping)
  316.         iErr = PlotIconSuite(&iconRect,alignment,transform,(*myGlobals)->iconSuite);
  317.     }
  318. }
  319. /*        
  320.      As I shouldn't access my module's resource file after initialization, I use
  321.      this routine to load in my STR# resources and convert them to regular
  322.      (non resource) relocatable blocks
  323. */
  324. Handle GetDetachedStrings(short id)
  325. {
  326.     Handle        strH;
  327.     strH = Get1Resource('STR#',id);
  328.     if (strH)
  329.     {
  330.         DetachResource(strH);
  331.     }
  332.     return(strH);
  333. }
  334. /*
  335.     IsPressed returns true if the given key is being pressed. I use this to
  336.     check the modifier key states 
  337. */
  338. Boolean IsPressed(unsigned short key)
  339. {
  340.     unsigned char keyMap[16];
  341.     GetKeys((unsigned long *)&keyMap);
  342.     return((keyMap[key>>3]>>(key & 7)) & 1);
  343. }
  344. /* 
  345.     The following is a technical improvement on my original HasDebugger()
  346.     routine. This is based on information found in a snippet under the path
  347.     sample code/snippets/platforms & tools/debuggerpresence, and also some
  348.     info in Think Reference
  349. */
  350. Boolean HasDebugger(void)
  351. {
  352.     char    *debugFlagPtr;
  353.     short    debugFlags;
  354.     if (Can32Bit()) // machine is capable of using 32-bit addressing (might be in 24-bit mode)
  355.     {
  356.         debugFlagPtr = (char *) 0xBFFL; // location of debugger info flags if 32 bit possible
  357.     }
  358.     else
  359.     {
  360.         debugFlagPtr = (char *) 0x120L; // location of debugger info flags if 32 bit impossible
  361.     }
  362.     debugFlags = *debugFlagPtr;
  363.     if (debugFlags & 1<<5) // test debugger present flag
  364.         return(TRUE);
  365.     else
  366.         return (FALSE);
  367. }
  368. Boolean Can32Bit(void) // can this machine be placed in 32-bit mode?
  369. {
  370.     long        addressingMode;
  371.     OSErr        iErr;
  372.     iErr = Gestalt(gestaltAddressingModeAttr, &addressingMode);
  373.     if (!iErr && (addressingMode & (1 << gestalt32BitCapable)))
  374.         return (TRUE);
  375.     else
  376.         return (FALSE);
  377. }